package com.fstec.ks.master.queue;

import java.io.File;
import java.nio.charset.Charset;
import java.util.concurrent.locks.ReentrantLock;

import org.apache.commons.io.FileUtils;

import com.sinotn.SinotnLogger;
import com.sinotn.SinotnRuntime;
import com.sinotn.error.MessageException;

public class MessageQueueLocal implements MessageQueue {
	private static final Charset charset=Charset.forName("UTF-8");
	private ReentrantLock lock=new ReentrantLock();
	private File folder;
	private String queueName;
	private int fileSize=8*1024*1024;// 8M
	private LocalFileWriter writer;
	private LocalFileReader reader;
	private int rcvBufferSize=8*1024;
	private int readBuffSize=8*1024;
	private String homePath;

	public void setFileSize(int fileSize) {
		this.fileSize = fileSize;
	}

	public void setRcvBufferSize(int rcvBufferSize) {
		if(rcvBufferSize>0){
			this.rcvBufferSize = rcvBufferSize;
		}
	}

	public void setReadBuffSize(int readBuffSize) {
		if(readBuffSize>0){
			this.readBuffSize = readBuffSize;
		}
	}
	public void close(boolean delete){
		if(this.writer!=null){
			this.writer.close();
			this.writer=null;
		}
		if(this.reader!=null){
			this.reader.close();
			this.reader=null;
		}
		if(this.folder!=null && this.folder.exists()){
			if(delete){
				try{
					FileUtils.deleteDirectory(this.folder);
				}catch(Throwable e){
					SinotnLogger.DEBUG.error("删除队列目录失败"+this.folder.getAbsolutePath(), e);
				}
			}
			this.folder=null;
		}
	}
	@Override
	public void init(String id) {
		try{
			if(this.queueName!=null && this.queueName.equals(id)) return;// 当前队列已初始化，不重复初始化
			File home=new File(SinotnRuntime.getHome(), "backup");
			if(!home.exists()){
				home.mkdir();
			}
			home=new File(home, "Queue");
			if(!home.exists()){
				home.mkdir();
			}
			if(this.folder!=null && !this.folder.getName().equals(id)){
				// 删除旧目录
				this.close(true);
			}
			
			this.folder=new File(home, id);
			if(!this.folder.exists()){
				this.folder.mkdir();
			}
			this.writer=new LocalFileWriter(this.folder, this.fileSize, this.rcvBufferSize);
			this.writer.init();
			this.reader=new LocalFileReader(this.folder, this.readBuffSize);
			this.reader.init();
			if(this.homePath==null){
				this.homePath=SinotnRuntime.getHome().getAbsolutePath();
			}
			this.queueName=id;
		}catch(Throwable e){
			this.writer=null;
			this.reader=null;
			this.folder=null;
			SinotnLogger.DEBUG.error("监控消息推送队列失败", e);
		}
	}

	@Override
	public void send(QueueMessage message) {
		this.lock.lock();
		try{
			byte[] data;
			this.writer.mark();
			// 消息类型;
			this.writer.write(message.getType());
			// 时间戳timestamp
			this.writer.write(System.currentTimeMillis());
			// 消息标识id
			String text=message.getId();
			data=text.getBytes(charset);
			this.writer.write((byte)data.length);
			this.writer.write(data);
			
			// 消息文本体bodyText
			text=message.getBodyText();
			if(text==null){
				this.writer.write(0);
			}else{
				data=text.getBytes(charset);
				this.writer.write(data.length);
				this.writer.write(data);
			}
			// 消息文件file
			File file=message.getFile();
			if(file==null){
				this.writer.write(0);
			}else{
				text=file.getAbsolutePath();
				if(text.startsWith(this.homePath)){
					text="home://"+text.substring(this.homePath.length());
				}
				data=text.getBytes(charset);
				this.writer.write(data.length);
				this.writer.write(data);
			}
			// 消息备注
			text=message.getDescText();
			if(text==null){
				this.writer.write(0);
			}else{
				data=text.getBytes(charset);
				this.writer.write(data.length);
				this.writer.write(data);
			}
			this.writer.flush();
		}catch(Throwable e){
			SinotnLogger.DEBUG.error("保存监控消息队列失败", e);
			this.writer.rollback();
			throw new MessageException("保存数据失败");
		}finally{
			lock.unlock();
		}
	}

	@Override
	public QueueMessage next() {
		if(this.reader==null) return null;
		return this.reader.next();
	}

	@Override
	public QueueMeta getMeta() {
		QueueMeta meta=new QueueMeta();
		if(this.writer!=null){
			meta.setWriteCount(this.writer.getWriteCount());
		}
		if(this.reader!=null){
			meta.setReadCount(this.reader.getReadCount());
		}
		return meta;
	}
}
